/************************************************************
 * Project Name         [Thinking_In_Java]
 * File Name            [Calculator.java]
 * Creation Date        [10-Jul-2014]
 * 
 * Copyright© ge.y.yang@gmail.com All Rights Reserved
 * 
 * Work hard, play harder, think big and keep fit
 ************************************************************/
package pkg_02_gui.calculator_v2.ui;

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.HeadlessException;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.IOException;

import javax.swing.AbstractAction;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.border.BevelBorder;

import pkg_02_gui.calculator_v2.about.About;

/**
 * 计算器界面
 * 
 * @author 不落的太阳(Sean Yang)
 * @version 1.0
 * @since JDK 6
 * 
 */
public class Calculator extends JFrame implements ActionListener {

	private static final long serialVersionUID = -2312844739408066295L;

	/** ==================菜单定义区================== */
	private final JMenuBar menuBar = new JMenuBar();

	private final JMenu menuEdit = new JMenu("编辑(E)");
	private final JMenuItem menuItemCopy = new JMenuItem("复制(C)", KeyEvent.VK_C);
	private final JMenuItem menuItemCut = new JMenuItem("粘贴(P)", KeyEvent.VK_V);

	private final JMenu menuView = new JMenu("查看(V)");
	private final JRadioButton boxStand = new JRadioButton("标准型(T)", true);
	private final JRadioButton boxScience = new JRadioButton("科学型(S)", false);
	private final JMenuItem menuItemMath = new JMenuItem("数学分组", KeyEvent.VK_I);

	private final JMenu menuHelp = new JMenu("帮助(H)");
	private final JMenuItem menuItemHelp = new JMenuItem("帮助主题", KeyEvent.VK_H);
	private final JMenuItem menuItemAbout = new JMenuItem("关于计算器",
			KeyEvent.VK_A);

	private final JPanel mPanel = new JPanel();
	private final JPanel clearPanel = new JPanel();
	private final JPanel buttonPanel = new JPanel();

	private final JTextField msg = new JTextField("0");
	private final CalculatorButton[] buttons = new CalculatorButton[27];
	private final JLabel inforLabel = new JLabel();

	/** 保存预执行操作的数 */
	private double value = 0;
	/** 是否已经保存 */
	private boolean hasSaved = false;
	/** 保存的数字 */
	private double saveNum = 0;
	/** 运算操作: 0无操作,1加,2减,3乘,4除 */
	private int operation = 0;
	/** 保存临时数据 */
	private StringBuffer tmp = new StringBuffer();
	/** 文字框允许输入的数字长度 */
	private final int allowLength = 32;

	private boolean hasPressed = false;

	/**
	 * 计算器界面类缺省构造函数
	 */
	public Calculator() {
		setSize(260, 240);
		setTitle("计算器");
		Toolkit tk = Toolkit.getDefaultToolkit();
		setLocation((tk.getScreenSize().width - getWidth()) / 2,
				(tk.getScreenSize().height - getHeight()) / 2);

		initMenu();
		initButton();
		initAdd();

		mPanel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0),
				"UpPress");
		mPanel.getActionMap().put("UpPress", new ButtonListener());

		setResizable(false);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setVisible(true);
	}

	/**
	 * 初始化菜单添加
	 */
	private void initMenu() {
		setJMenuBar(menuBar);

		menuBar.add(menuEdit);
		menuEdit.setMnemonic(KeyEvent.VK_E);
		menuEdit.add(menuItemCopy);
		menuItemCopy.setMnemonic(KeyEvent.VK_C);
		menuEdit.add(menuItemCut);
		menuItemCut.setMnemonic(KeyEvent.VK_P);

		menuBar.add(menuView);
		menuView.setMnemonic(KeyEvent.VK_V);
		ButtonGroup group = new ButtonGroup();
		group.add(boxStand);
		group.add(boxScience);
		menuView.add(boxStand);
		menuView.add(boxScience);
		menuView.addSeparator();
		menuView.add(menuItemMath);

		menuBar.add(menuHelp);
		menuHelp.setMnemonic(KeyEvent.VK_H);
		menuHelp.add(menuItemHelp);
		menuHelp.addSeparator();
		menuHelp.add(menuItemAbout);

		menuItemCopy.addActionListener(this);
		menuItemCut.addActionListener(this);
		menuItemAbout.addActionListener(this);
	}

	/**
	 * 初始化按钮. 按钮的初始化, 部署, 事件添加等
	 */
	private void initButton() {
		ButtonListener listener = new ButtonListener();
		/** *************************运算符************************* */
		buttons[0] = new CalculatorButton(listener, "=", KeyEvent.VK_EQUALS,
				false);
		buttons[1] = new CalculatorButton(listener, "+", KeyEvent.VK_ADD,
				false, Color.RED);
		buttons[2] = new CalculatorButton(listener, "-", KeyEvent.VK_SUBTRACT,
				false, Color.RED);
		buttons[3] = new CalculatorButton(listener, "*", KeyEvent.VK_MULTIPLY,
				false, Color.RED);
		buttons[4] = new CalculatorButton(listener, "/", KeyEvent.VK_DIVIDE,
				false, Color.RED);
		buttons[5] = new CalculatorButton(listener, "1/x", KeyEvent.VK_R, false);
		buttons[6] = new CalculatorButton(listener, "+/-", KeyEvent.VK_F9,
				false);
		buttons[7] = new CalculatorButton(listener, "sqrt", KeyEvent.VK_EQUALS,
				false);
		buttons[8] = new CalculatorButton(listener, "%", '%', false);
		buttons[9] = new CalculatorButton(listener, ".", KeyEvent.VK_PERIOD,
				false);

		/** *************************数字************************* */
		buttons[10] = new CalculatorButton(listener, "0", KeyEvent.VK_0, false);
		buttons[11] = new CalculatorButton(listener, "1", KeyEvent.VK_1, false);
		buttons[12] = new CalculatorButton(listener, "2", KeyEvent.VK_2, false);
		buttons[13] = new CalculatorButton(listener, "3", KeyEvent.VK_3, false);
		buttons[14] = new CalculatorButton(listener, "4", KeyEvent.VK_4, false);
		buttons[15] = new CalculatorButton(listener, "5", KeyEvent.VK_5, false);
		buttons[16] = new CalculatorButton(listener, "6", KeyEvent.VK_6, false);
		buttons[17] = new CalculatorButton(listener, "7", KeyEvent.VK_7, false);
		buttons[18] = new CalculatorButton(listener, "8", KeyEvent.VK_8, false);
		buttons[19] = new CalculatorButton(listener, "9", KeyEvent.VK_9, false);

		/** *************************M键************************* */
		buttons[20] = new CalculatorButton(listener, "MC", KeyEvent.VK_L, true,
				Color.RED);
		buttons[21] = new CalculatorButton(listener, "MR", KeyEvent.VK_R, true,
				Color.RED);
		buttons[22] = new CalculatorButton(listener, "MS", KeyEvent.VK_M, true,
				Color.RED);
		buttons[23] = new CalculatorButton(listener, "M+", KeyEvent.VK_P, true,
				Color.RED);
		buttons[24] = new CalculatorButton(listener, "Backspace",
				KeyEvent.VK_BACK_SPACE, false, Color.RED, 62, 25);
		buttons[25] = new CalculatorButton(listener, "CE", KeyEvent.VK_DELETE,
				false, Color.RED, 62, 25);
		buttons[26] = new CalculatorButton(listener, "C", KeyEvent.VK_ESCAPE,
				false, Color.RED, 62, 25);
	}

	/**
	 * 初始化各个容器的添加
	 */
	private void initAdd() {
		// 初始化输入框
		msg.setSize(240, 20);
		msg.setLocation(6, 4);
		msg.setEditable(false);
		msg.setBackground(Color.WHITE);
		msg.setMargin(new Insets(0, 6, 0, 8));
		msg.setHorizontalAlignment(JTextField.RIGHT);

		inforLabel.setSize(30, 26);
		inforLabel.setLocation(8, 30);
		inforLabel.setBorder(new BevelBorder(BevelBorder.LOWERED));
		inforLabel.setHorizontalAlignment(SwingConstants.CENTER);

		mPanel.setSize(35, 150);
		mPanel.setLocation(6, 60);
		mPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 3, 3));

		// 增加MC, MR, MS, M+
		for (int i = 20; i < 24; i++)
			mPanel.add(buttons[i]);

		clearPanel.setSize(200, 26);
		clearPanel.setLocation(45, 30);
		clearPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 3, 0));

		// 增加Backspace, CE, C
		for (int i = 24; i < 27; i++)
			clearPanel.add(buttons[i]);

		buttonPanel.setSize(200, 150);
		buttonPanel.setLocation(45, 60);
		// panBtn.setBorder(b);
		buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 4, 3));
		buttonPanel.add(buttons[17]);// 7
		buttonPanel.add(buttons[18]);// 8
		buttonPanel.add(buttons[19]);// 9
		buttonPanel.add(buttons[4]);// ÷
		buttonPanel.add(buttons[7]);// sqrt
		buttonPanel.add(buttons[14]);// 4
		buttonPanel.add(buttons[15]);// 5
		buttonPanel.add(buttons[16]);// 6
		buttonPanel.add(buttons[3]);// ×
		buttonPanel.add(buttons[8]);// %
		buttonPanel.add(buttons[11]);// 1
		buttonPanel.add(buttons[12]);// 2
		buttonPanel.add(buttons[13]);// 3
		buttonPanel.add(buttons[2]);// -
		buttonPanel.add(buttons[5]);// 1/x
		buttonPanel.add(buttons[10]);// 0
		buttonPanel.add(buttons[6]);// +/-
		buttonPanel.add(buttons[9]);// .
		buttonPanel.add(buttons[1]);// +
		buttonPanel.add(buttons[0]);// =

		setLayout(null);
		add(msg);
		add(inforLabel);
		add(mPanel);
		add(clearPanel);
		add(buttonPanel);
	}

	/**
	 * 处理按钮事件 <br>
	 * 1.复制事件<br>
	 * 2.粘贴事件
	 * [此处应用正则表达式(详细请参考类java.util.regex.Pattern)解析粘贴板中的内容,仅得到内容中最后的数字和小数点]<br>
	 * 3.关于事件<br>
	 */
	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == menuItemCopy) {
			msg.selectAll();
			msg.copy();
		}
		if (e.getSource() == menuItemCut) {
			try {
				Transferable transfer = Toolkit.getDefaultToolkit()
						.getSystemClipboard().getContents(null);
				if (transfer != null
						&& transfer
								.isDataFlavorSupported(DataFlavor.stringFlavor)) {
					// 得到剪贴板中的字符串
					String text = transfer.getTransferData(
							DataFlavor.stringFlavor).toString();
					// 得到字符串中的数字和.得到的是数组
					String[] sp = text.split("[\\D&&[^.]]");
					// 从数组中得到最后一个数字
					if (sp.length > 0) {
						String str = sp[sp.length - 1];
						System.out.println(str);
						// 对得到的数字再次以.分割
						String[] sp2 = str.split("\\.");
						System.out.println(sp2.length);
						// 对于数组长度大于2的得到后两个数组成的小数
						if (sp2.length > 1) {
							String x = sp2[sp2.length - 2];
							text = (x.equals("") ? "0" : x) + "."
									+ sp2[sp2.length - 1];
						}
						// 对于数组长度等于0的
						else
							text = sp2[sp2.length - 1];
						msg.setText(text);
					}

				}
			} catch (HeadlessException e1) {
				System.out.println("错误:" + e1.getMessage());
			} catch (UnsupportedFlavorException e1) {
				System.out.println("错误:" + e1.getMessage());
			} catch (IOException e1) {
				System.out.println("错误:" + e1.getMessage());
			}
		}
		if (e.getSource() == menuItemAbout) {
			new About(this, "关于本计算器", true);
		}

	}

	/**
	 * 按钮事件,包括+, -, *, /, 1/x, 数字等按钮事件<br>
	 * 此类继承AbstractAction
	 */
	private class ButtonListener extends AbstractAction {

		private static final long serialVersionUID = 2498607120274909538L;

		@Override
		public void actionPerformed(ActionEvent e) {
			int i = 0;
			for (i = 0; i < buttons.length; i++) {
				if (e.getActionCommand().equals(buttons[i].getText()))
					break;
			}
			double value2;
			try {
				// 获得输入栏中的数字
				value2 = Double.parseDouble(msg.getText());
			} catch (NumberFormatException e1) {
				System.out.println("错误:" + e1.getMessage());
				value2 = 0;
			}
			switch (i) {
			case 0:
				if (operation != 0) {
					double result = 0;
					switch (operation) {
					case 1:
						result = value + value2;
						break;
					case 2:
						result = value - value2;
						break;
					case 3:
						result = value * value2;
						break;
					case 4:
						result = value / value2;
						break;
					}
					showResult(result + "");
					hasPressed = false;
				}
				break;
			// +, -, *, /
			case 1:
			case 2:
			case 3:
			case 4:
				if (operation != 0 && hasPressed) {
					countResult(value2);
				}
				value = Double.parseDouble(msg.getText());
				if (tmp.length() > 0) {
					tmp = new StringBuffer();
				}
				operation = i;
				break;
			case 5: // 1/x
				if (value2 != 0)
					showResult((1 / value2) + "");
				else
					showResult("");
				break;
			case 6: // +/-
				if (value2 != 0)
					showResult((value2 * -1) + "");
				break;
			case 7: // sqrt
				if (value2 != 0)
					showResult(Math.sqrt(value2) + "");
				break;
			case 8: // %
				showResult((value * value2 / 100) + "");
				break;
			case 9: // .
				if (isContain(tmp.toString(), "."))
					break;
				if (value2 == 0)
					tmp.append(0);
				value2 = -1;
			case 10: // 0-9
				if (value2 == 0)
					break;
			case 11:
			case 12:
			case 13:
			case 14:
			case 15:
			case 16:
			case 17:
			case 18:
			case 19:
				if (tmp.length() <= allowLength) {
					tmp.append(buttons[i].getText());
					msg.setText(tmp.toString());
					if (operation != 0 && hasPressed == false)
						hasPressed = true;
				}
				break;
			case 20: // MC
				if (hasSaved) {
					saveNum = 0;
					hasSaved = false;
					inforLabel.setText("");
				}
				break;
			case 21: // MR
				String result = saveNum + "";
				msg.setText(result.endsWith(".0") ? result.substring(0,
						result.length() - 2) : result);
				break;
			case 22: // MS
				if (value2 != 0) {
					saveNum = value2;
					hasSaved = true;
					inforLabel.setText("M");
				}
				break;
			case 23: // M+
				if (value2 != 0) {
					saveNum += value2;
					hasSaved = true;
					inforLabel.setText("M");
				}
				break;
			case 24: // Backspace
				if (tmp.length() == 1)
					showResult("0");
				if (tmp.length() > 1) {
					tmp.deleteCharAt(tmp.length() - 1);
					msg.setText(tmp.toString());
				}
				break;
			case 25: // CE
				clearAll("0");
				break;
			case 26: // C
				clearAll("0");
				break;
			}
		}
	}

	/**
	 * 检测某字符串中是否包含某个字符串
	 * 
	 * @param str
	 *            待检测的字符串
	 * @param ch
	 *            要包含的字符串
	 * @return 包含返回true, 否则false
	 */
	private boolean isContain(String str, String ch) {
		return str.indexOf(ch) != -1;
	}

	/**
	 * 设置计算的得到的结果
	 * 
	 * @param result
	 *            需要设置的结果
	 */
	private void showResult(String result) {
		msg.setText(result.endsWith(".0") ? result.substring(0,
				result.length() - 2) : result);
		tmp = new StringBuffer();
	}

	/**
	 * 清空结果
	 * 
	 * @param result
	 *            需要设置的值
	 */
	private void clearAll(String result) {
		showResult(result);
		value = 0;
		operation = 0;
		hasPressed = false;
	}

	/**
	 * 计算结果并显示结果
	 * 
	 * @param value2
	 *            第二个操作数
	 */
	private void countResult(double value2) {
		double result = 0;
		switch (operation) {
		case 1:
			result = value + value2;
			break;
		case 2:
			result = value - value2;
			break;
		case 3:
			result = value * value2;
			break;
		case 4:
			result = value / value2;
			break;
		}
		showResult(result + "");
		hasPressed = false;
		value = result;
	}
}
